package com.bowen.util.impl;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import com.bowen.model.inf.DataSourcePropertiesInterface;
import com.bowen.util.DataSourceInterface;

/**
 * 指定数据源操作实现类
 * 
 * @author Bowen
 *
 */
// @Component
public class DataSourceImpl implements DataSourceInterface {

  volatile static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();

  /**
   * 获取连接
   * 
   * @param tdProperties 连接信息
   * @throws Exception 连接异常
   */
  public void getConnection(DataSourcePropertiesInterface tdProperties) throws Exception {
    // threadLocal = new ThreadLocal<Connection>();
    Connection conn = (Connection) threadLocal.get();
    if (conn == null) {
      threadLocal.set(
          DriverManager.getConnection(tdProperties.getUrl(), tdProperties.getUsername(), tdProperties.getPassword()));
    }

  }

  /**
   * 执行批SQL语句 暂时弃用
   * 
   * @param conn 连接
   * @param sqls sql
   * @throws Exception 连接异常
   */
  @Deprecated
  protected void goBatch(Connection conn, String[] sqls) throws Exception {
    conn.setAutoCommit(false);
    if (sqls == null) {
      return;
    }
    Statement sm = null;
    try {
      sm = conn.createStatement();
      for (int i = 0; i < sqls.length; i++) {
        sm.addBatch(sqls[i]);// 将所有的SQL语句添加到Statement中
      }
      // 一次执行多条SQL语句
      sm.executeBatch();
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }

  @Override
  public <T> List<T> query(DataSourcePropertiesInterface properties, Class<T> clazz, String sql) throws Exception {
    // 获取连接
    getConnection(properties);
    try {
      // 执行SQL
      // goBatch(threadLocal.get(), sqls);
      // 拿数据
      return getData(clazz, threadLocal.get(), sql);
    } finally {
      // close
      Optional.ofNullable(threadLocal.get()).ifPresent(con -> {
        try {
          con.close();
        } catch (SQLException e) {
          e.printStackTrace();
        }
      });
    }
  }

  protected <T> List<T> getData(Class<T> clazz, Connection conn, String sql) throws SQLException {
    Field[] f = clazz.getDeclaredFields(); // 获取该类的字段
    List<T> result = new ArrayList<T>();
    PreparedStatement pst = null;
    ResultSet rs = null;
    try {
      pst = conn.prepareStatement(sql);
      rs = pst.executeQuery();
      // 防止OOM?
      rs.setFetchSize(20);
      // rs.setFetchSize(Integer.MIN_VALUE);
      // rs.setFetchDirection(ResultSet.FETCH_REVERSE);
      while (rs.next()) {
        result.add(getFiled(clazz, rs, f));
      }
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      Optional.ofNullable(pst).ifPresent(s -> {
        try {
          s.close();
        } catch (SQLException e) {
          e.printStackTrace();
        }
      });
      Optional.ofNullable(rs).ifPresent(s -> {
        try {
          s.close();
        } catch (SQLException e) {
          e.printStackTrace();
        }
      });
    }
    return result;
  }

  public static void main(String[] args) {
    // getFiled(TdProperties.class);
  }

  static protected <T> T getFiled(Class<T> clazz, ResultSet rs, Field[] f) throws Exception {
    T t = clazz.getDeclaredConstructor().newInstance();
    for (Field ff : f) // 遍历字段
    {

      Optional.ofNullable(rs.getString(ff.getName())).ifPresent(v -> {
        try {
          ff.setAccessible(true);
          ff.set(t, v);
        } catch (IllegalArgumentException | IllegalAccessException e) {
          e.printStackTrace();
        }
      });
      // System.out.println(ff.getName()); //获取字段名
      // System.out.println(ff.getType().getName()); //获取字段类型的名称
    }
    return t;
  }

}
